﻿using System;
using System.Collections.Generic;
using System.Linq;
using StockFinder.Model;

namespace StockFinder.Indicators.Day.ClosePrice
{
    public class ExponentialMovingAverageWilderRelativeStrengthIndexClosePriceDayIndicator : BaseDayIndicator
    {        
        public ExponentialMovingAverageWilderRelativeStrengthIndexClosePriceDayIndicator(int lookbackPeriod, string indicatorName) : base(lookbackPeriod, indicatorName)
        {
        }

        public override void ApplyIndicator(List<DailyPrice> prices)
        {
            if (!Initialize(prices)) return;

            IOrderedEnumerable<DailyPrice> orderedPrices = prices.OrderBy(p => p.PriceDate);

            DailyPrice[] pricesArray = orderedPrices.ToArray();
            DailyPrice currentPrice = null;
            int pricesCount = pricesArray.Count();
            IEnumerable<DailyPrice> skippedPrices = null;
            DailyPrice[] takenPrices = null;
            int numberToSkip = 0;
            decimal change = 0;
            decimal averageGain = 0;
            decimal averageLoss = 0;
            decimal rs = 0;
            decimal rsi = 0;
            DailyPrice previousPrice = null;

            //start from 50
            for (int i = (LookbackPeriod); i < pricesCount; i++)
            {
                currentPrice = pricesArray[i];
                previousPrice = pricesArray[i - 1];

                if (i == LookbackPeriod)
                {
                    numberToSkip = i - LookbackPeriod;

                    skippedPrices = pricesArray.Skip(numberToSkip);

                    takenPrices = skippedPrices.Take(LookbackPeriod + 1).ToArray();

                    decimal cummulativeGain = 0;
                    decimal cummulativeLoss = 0;

                    //first need to get moving average
                    for (int j = 1; j < takenPrices.Count(); j++)
                    {
                        previousPrice = takenPrices[j - 1];
                        currentPrice = takenPrices[j];

                        change = currentPrice.AdjustedClose - previousPrice.AdjustedClose;

                        if (change > 0)
                        {
                            cummulativeGain += change;
                        }
                        else
                        {
                            cummulativeLoss += Math.Abs(change);
                        }
                    }

                    averageGain = cummulativeGain / LookbackPeriod;
                    averageLoss = cummulativeLoss / LookbackPeriod;
                }
                else
                {
                    change = currentPrice.AdjustedClose - previousPrice.AdjustedClose;

                    //calc smoothed average
                    if (change > 0)
                    {
                        averageGain = ((averageGain * (LookbackPeriod-1)) + change) / LookbackPeriod;
                        averageLoss = (averageLoss * (LookbackPeriod - 1)) / LookbackPeriod;
                    }
                    else
                    {
                        averageGain = (averageGain * (LookbackPeriod - 1)) / LookbackPeriod;
                        averageLoss = ((averageLoss * (LookbackPeriod - 1)) + Math.Abs(change)) / LookbackPeriod;
                    }
                }

                if (averageGain == 0)
                {
                    rsi = 0;
                }
                else if (averageLoss == 0)
                {
                    rsi = 100;
                }
                else
                {
                    rs = averageGain / averageLoss;
                    rsi = 100 - (100 / (1 + rs));
                }

                currentPrice.DayIndicators[IndicatorName] = rsi;
            }
        }       
    }
}
